<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>this绑定规制四-显示绑定(This binding regulation four - Display binding)</title>
  <!-- 
  在JavaScript中，this关键字的行为受到多种规则的影响，其中显示绑定（Display Binding）是第四个重要的规则。显示绑定是指通过call()、apply()或bind()方法显式指定this的值。
  一、显示绑定的定义
  显示绑定是指通过调用函数时使用call()、apply()或bind()方法，显式地将this绑定到特定的对象上。这种方式允许开发者控制函数执行时this的指向。

  二、显示绑定的方法
  1. call() 方法：
    - call() 方法调用一个函数，并指定this的值为第一个参数。后续参数将作为函数的参数传递。
    function greet() {
      console.log(`Hello, my name is ${this.name}`);
    }

    const person = { name: 'Alice' };
    greet.call(person); // 输出: Hello, my name is Alice
  在这个例子中，greet函数通过call()方法被调用，this指向person对象。

  2. apply() 方法：
    - apply() 方法与call()类似，但它接受一个数组作为参数，用于传递给函数。
    function introduce(greeting) {
      console.log(`${greeting}, my name is ${this.name}`);
    }

    const person = { name: 'Bob' };
    introduce.apply(person, ['Hi']); // 输出: Hi, my name is Bob
  在这个例子中，introduce函数使用apply()方法被调用，this同样指向person对象。

  3. bind() 方法：
    - bind() 方法创建一个新的函数，并将this绑定到指定的对象。与call()和apply()不同，bind()不会立即执行函数，而是返回一个新的函数。
    function sayHello() {
      console.log(`Hello, my name is ${this.name}`);
    }

    const person = { name: 'Charlie' };
    const boundSayHello = sayHello.bind(person);
    boundSayHello(); // 输出: Hello, my name is Charlie
  在这个例子中，sayHello函数通过bind()方法被绑定到person对象上，返回的新函数在调用时this指向person。

  三、注意事项
  1. 优先级：
    - 显示绑定的优先级高于其他绑定规则（如隐式绑定和默认绑定）。如果使用了call()、apply()或bind()，this将始终指向指定的对象。

  2. 返回值：
    - 使用bind()方法返回的新函数可以在后续的任何地方调用，而不需要再次指定this。

  四、总结
  - 显示绑定是通过call()、apply()或bind()方法显式指定this的值。
  - call()和apply()立即调用函数，而bind()返回一个新的函数。
  - 显示绑定的优先级高于其他绑定规则，允许开发者控制this的指向。
   -->
</head>

<body>

  <script>
    // 1. 显示绑定
    const obj = {
      name: 'Alice',
    };

    function foo() {
      console.log("foo's this: ", this);
    }

    // 执行函数,并且函数中的this指向obj
    obj.foo = foo;
    obj.foo(); // 输出: foo's this:  { name: 'Alice' }

    // 2. call() 方法
    function introduce(greeting) {
      console.log(`${greeting}, my name is ${this.name}`);
    }

    const person = { name: 'Bob' };
    introduce.call(person, 'Hello'); // 输出: Hello, my name is Bob

    // 3. apply() 方法
    function greet(greeting, punctuation) {
      console.log(`${greeting}, my name is ${this.name}${punctuation}`);
      return "myApply"
    }

    Function.prototype.createApply = function (context, args) {
      context = context || window
      const fnSymbol = Symbol()
      context[fnSymbol] = this
      const result = context[fnSymbol](...args) // 隐式绑定执行函数
      delete context[fnSymbol]
      return result
    }

    const person2 = { name: 'Charlie' };
    greet.createApply(person2, ['Hi', '!']); // 输出: Hi, my name is Charlie!

    // 4. bind() 方法
    function sayHello() {
      console.log(`Hello, my name is ${this.name}`);
    }

    const person3 = { name: 'David' };
    const sayHelloToDavid = sayHello.bind(person3);
    sayHelloToDavid(); // 输出: Hello, my name is David


  </script>

</body>

</html>